【PIC24FJ64GA002】OutputCompare機能を使ってPWMを出力してみる。

2021年2月21日

OutputCompare機能を使ってPWMを出力します。
前段:PWM(PluseWidthModulation)はLED照度やFANモータの回転数を制御するのに適した出力波形です。PWMとは。。。周期を一定とし、ON時間の幅(長さ)とOFF時間の幅(長さ)の比をDuty比と呼び、
その比を変更する方式です。
PWMの代表的な回路図とその制御波形を下図に示します。

図:PWM制御の代表図とスイッチング素子に加わるパルス波形の例

負荷にLEDを接続したときを例に説明します。
スイッチング素子のON時間の間だけLEDは点灯状態になります。
OFF時間はLEDは消灯します。これを一定の周期で繰り返します。
周波数を100Hz以上にすると人間の目ではON/OFFをとらえることが出来ません。
ON時間を長くするとLEDは明るく見え、ON時間を短くするとLEDは暗く見えるようになります。
具体的にPICの設定をしていきます。

出力ポートの設定

PIC24FJ64GA002にはOutputCompareが1~5まであります。
PPS(PeripheralPinSelect)機能を使ってRB15にOC1(OutputCompare)を出力として割り当ててみます。
出力設定サンプルコードは↓
RPOR7bits.RP15R = 18;
RPOR7レジスタのRP15(14~12)の値を"18″にしています。”18″はOC1を意味しています。
詳細はデータシートDS39881Eのpage109のTable10-3の出力マップを参照。

周期を作成。1MHzのパルスを出力したい場合。

TIMER2をOutputCompareのクロックソースとして利用します。
1MHzの逆数は1μsecとなります。それに合わせて周期レジスタPR2の値を設定する必要があります。

PR2={1μsec/(Tcy×PS)}-1 ・・・①

PIC24FJ64GA002を内蔵クロックで最速駆動させた場合Fcyは16MHzとなります。
その逆数がTcy:0.0625μsecです。PS(ポストスケーラ)は"1″とします。
それぞれを式①に代入すると
PR2={1usec/(0.0625usec×1)}-1=15と求まります。
2で割り切れないのは都合が悪いのでPR2を"16″に修正します。

ON時間はOCxRレジスタで設定

OC1を使用しているのでOC1Rを使用しましょう。
レジスタに代入できる値の条件として
 ・PR2>OCxR。
 ・レジスタサイズは16bit。
以上から入力できる値は65535まで入るが16より小さい値にする必要があります。
今回はOC1Rは"8″とします。DUTY比は50%となります。
TMR2が"0″からカウントアップしてゆき、OC1Rで設定された値に達するとOC1ピンがLOWに切り替わります。
詳細はリファレンスマニュアルDS39706A_JPの16ページの図16-17を参照ください。

図:リファレンスマニュアルDS39706AよりOCのPWMモードの説明図

OCxCONレジスタでPWMモードに設定する。

OC1CONレジスタのOCMビットを"110″にするとPWMモードにすることが出来ます。
PWM設定サンプルコードは↓
OC1CONbits.OCM = 0B110;

回路図

RB15からパルス出力されるのを確認します。

図:PIC24FJ64GA002でPWM出力を確認

RB15の出力をオシロスコープで確認します。

OC1R=6、DUTY比50%時の出力波形はこちら↓

図:OC1R=8、Duty比50%時のRB15出力確認。

ON時間とOFF時間が均等に繰り返されていることが確認できますね。

OC1Rを”2”に変更しています。Duty比は12.5%です。

図:OC1R=2、Duty比12.5%時のRB15の確認。

OC1Rを"2″にするとON時間が短くなったことが確認できました。

全体のソースはこちら↓

// CONFIG2
#pragma config POSCMOD = NONE           // Primary Oscillator Select (Primary oscillator disabled)
#pragma config I2C1SEL = PRI            // I2C1 Pin Location Select (Use default SCL1/SDA1 pins)
#pragma config IOL1WAY = ON             // IOLOCK Protection (Once IOLOCK is set, cannot be changed)
#pragma config OSCIOFNC = ON            // Primary Oscillator Output Function (OSC2/CLKO/RC15 functions as port I/O (RC15))
#pragma config FCKSM = CSDCMD           // Clock Switching and Monitor (Clock switching and Fail-Safe Clock Monitor are disabled)
#pragma config FNOSC = FRCPLL           // Oscillator Select (Fast RC Oscillator with PLL module (FRCPLL))
#pragma config SOSCSEL = SOSC           // Sec Oscillator Select (Default Secondary Oscillator (SOSC))
#pragma config WUTSEL = LEG             // Wake-up timer Select (Legacy Wake-up Timer)
#pragma config IESO = OFF               // Internal External Switch Over Mode (IESO mode (Two-Speed Start-up) disabled)

// CONFIG1
#pragma config WDTPS = PS32768          // Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128            // WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = OFF             // Watchdog Timer Window (Windowed Watchdog Timer enabled; FWDTEN must be 1)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (Watchdog Timer is disabled)
#pragma config ICS = PGx1               // Comm Channel Select (Emulator EMUC1/EMUD1 pins are shared with PGC1/PGD1)
#pragma config GWRP = OFF               // General Code Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF                // General Code Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = OFF             // JTAG Port Enable (JTAG port is disabled)

//== include
#include "xc.h"

int main(void) {
    //== CLOCK_setup ========================================================
    CLKDIV = 0;               //PLL_setup_1:1
    //== AD1PCGF ==========================================================
    AD1PCFG = 0xffff;   //all_digital
    //=== TRISA ===========================================================
    TRISA = 0x0000;            //all_output
    //== TRISB =============================================================
    TRISB = 0x0000;            //all_output
    //== TIMER2 =========================================================
    T2CONbits.TON = 0;      //<15>Timer2_OFF
    T2CONbits.TSIDL = 1;        //<13>idlemode_stop
    T2CONbits.TGATE = 0;        //<6>gated_time_OFF
    T2CONbits.TCKPS = 0B00;      //<5-4>PS1:1
    T2CONbits.T32 = 0;      //<3>32bitmode_off
    T2CONbits.TCS = 0;      //<1>clock_source?internal
        IEC0bits.T2IE = 0;    //<7>interrupt_disable
        IPC1bits.T2IP = 1;    //<14-12>interrupt_priorty_0
        TMR2 = 0x00;
        PR2 = 16;    //<15-0>1usec/(0.0625u*1)-1=15
    //== CompareOut(PWM) ===================================
    RPOR7bits.RP15R = 18;  //<12-8>using_RP15_as_OC1(function_nunber_is_"18")
    OC1CONbits.OCTSEL = 0;    //<3>Timer2_is_source_clock_OC1
    OC1CONbits.OCM = 0B000;      //<2-0>OS1_is_disable
    OC1R = 0;                   //<15-0>OC1R_zero
    //== timer2_start =========================================
    T2CONbits.TON = 1;      //<15>T2_enable
    OC1CONbits.OCM = 0B110;     //<2-0>PWM_mode
    OC1R = 8;                  //<15-0>OC1_period_register

    while(1){

    }
}

よろしければバナーをクリックお願いします!